/**
  ETFRoot project, Anyang Normal University && IMP-CAS
  \class ETFUnpackTask
  \brief abstract base class for tasks in the unpacking stage
  \author SUN Yazhou, asia.rabbit@163.com
  \since 2021-10-04
  \date 2022-04-27 last modified
  \attention
  changelog
  <table>
  <tr>  <th>Date         <th>Author      <th>Description                   </tr>
  <tr>  <td>2021-10-04   <td>Asia Sun    <td>file created                  </tr>
  </table>

  \copyright Copyright (c) 2021 Anyang Normal U. && IMP-CAS with LGPLv3 LICENSE
*/

#include <TFolder.h>
#include <TH1F.h>
#include <TH2F.h>
#include <TClonesArray.h>
#include "ETFUnpackTask.h"
#include "FairRootManager.h"
#include "ETFMsg.h"
#include "ETFPXISection.h"
#include "ETFPXIFragment.h"
#include "ETFVMEEvent.h"
#include "ETFVMERawEvent.h"
#include "ETFHPTDCChannel.h"
#include "ETFAmplitudeChannel.h"
#include "ETFOfflineSource.h"

ClassImp(ETFUnpackTask);

ETFUnpackTask::ETFUnpackTask(const char *name, int verbose) : FairTask(name, verbose),
    fDebug(false), fPXISection(0), fVMEEvent(0), fVMERawEvent(0), fFolder(0){}

ETFUnpackTask::~ETFUnpackTask(){
  if(fFolder){ delete fFolder; fFolder = nullptr; }
} // end dtor


void ETFUnpackTask::Exec(Option_t *opt){
  if(!fPXISection && !fVMEEvent && !fVMERawEvent)
    ETFMsg::Error("ETFUnpackTask", "Exec: null member event pointer(s)");
  // --------------------- PXI PART ------------------------------ //
  if(fPXISection){
    hSecLen->Fill(fPXISection->GetSectionLength());
    for(TObject *fragObj : *fPXISection->GetFragments()){
      ETFPXIFragment *frag = dynamic_cast<ETFPXIFragment *>(fragObj);
      if(!frag) ETFMsg::Error("ETFUnpackTask", "Exec: null fragment encountered");
      const fragment_head &frag_h = frag->GetFragmentHead();
      hFragLen->Fill(frag_h.start_channel, frag_h.data_len);
    } // end for over fragments
    // ================ read HPTDC channles ====================== //
    TClonesArray *tchs = fPXISection->GetHPTDCChannels();
    for(TObject *tchObj : *tchs){
      ETFHPTDCChannel *tch = dynamic_cast<ETFHPTDCChannel *>(tchObj);
      if(!tch) ETFMsg::Error("ETFUnpackTask", "Exec: null PXI HPTDC channel encountered");
      const int chid = tch->GetChannelId();
      const int nl = tch->GetNofLeadingEdges(), nt = tch->GetNofTrailingEdges();

      hCh->Fill(chid); hnlvsChid->Fill(chid, nl); hntvsChid->Fill(chid, nt);
      hnl_ntvsChid->Fill(chid, nl - nt);
      if(nl > 0 && nt > 0) htot->Fill(chid, tch->GetTrailingEdge(0) - tch->GetLeadingEdge(0));
    } // end for over HPTDC channels
    if(fDebug){
      fPXISection->Print();
      getchar();
    } // end if(fDebug)
  } // end if(PXISection)
  // --------------------- VME PART ------------------------------ //
  if(fVMEEvent && fVMERawEvent){
    for(TObject *tchObj : *fVMEEvent->GetHPTDCChannels()){
      ETFHPTDCChannel *tch = dynamic_cast<ETFHPTDCChannel *>(tchObj);
      if(!tch) ETFMsg::Error("ETFUnpackTask", "Exec: null VME HPTDC channel encountered");
      const int chid = tch->GetChannelId();
      const int nl = tch->GetNofLeadingEdges(), nt = tch->GetNofTrailingEdges();

      hCh->Fill(chid); hnlvsChid->Fill(chid, nl); hntvsChid->Fill(chid, nt);
      hnl_ntvsChid->Fill(chid, nl - nt);
      if(nl > 0 && nt > 0) htot->Fill(chid, tch->GetTrailingEdge(0) - tch->GetLeadingEdge(0));
    } // end for over HPTDC channels
    if(fDebug){
      fVMEEvent->Print();
      fVMERawEvent->Print();
      getchar();
    } // end if(fDebug)
  } // end if(fVMEEVent && fVMERawEvent)
} // end member function Exec


InitStatus ETFUnpackTask::Init(){
  FairRootManager *man = FairRootManager::Instance();
  if(!man){
    ETFMsg::Error("ETFUnpackTask", "CreateHistos: FairRootManager not found");
    return kERROR;
  } // end if

  SourceType type = dynamic_cast<ETFOfflineSource *>(man->GetSource())->GetType();
  /// decoded PXI data, stored in TClonesArray, section-fragment format reserved
  switch(type){
    case SourceType::kPXISOURCE: case SourceType::kMIXEDSOURCE:
      fPXISection = (ETFPXISection *)man->GetObject("PXISection");
      if(SourceType::kPXISOURCE == type) break;
    case SourceType::kVMESOURCE:
      /// decoded VME data, stored in TClonesArray
      fVMEEvent = (ETFVMEEvent *)man->GetObject("VMEEvent");
      /// primitive adc, qdc and scaler data
      fVMERawEvent = (ETFVMERawEvent *)man->GetObject("VMERawEvent");
      break;
    default:
      ETFMsg::Error("ETFUnpackTask", "Init: Illigal source type");
      break;
  } // end switch

  CreateHistos();

  return kSUCCESS;
} // end member function Init()

void ETFUnpackTask::FinishTask(){
  WriteHistos();
  dynamic_cast<ETFOfflineSource *>(FairRootManager::Instance()->GetSource())->PrintSummary();
} // end member function FinishTask

void ETFUnpackTask::WriteHistos(){
  fFolder->Write("", TObject::kOverwrite);
} // end member function WriteHistos

void ETFUnpackTask::CreateHistos(){
  fFolder = new TFolder("UnpackTask", "Statistics for the Unpacking Stage");
  fFolder->SetOwner(); // objects are owned by the folder, and deleted along with it

  hSecLen = new TH1F("hSecLen", "Data Section Length;words", 2001, -0.5, 2000.5);
  hFragLen = new TH2F("hFragLen", "Fragment Data Length;start channel;words",
    11, -500., 10500., 201, -0.5, 200.5);
  hCh = new TH1F("hCh", "Signal Channel Distribution among Channel IDs;channelId",
    10001, -0.5, 10000.5);
  htot = new TH2F("htot", "Time Over Threshold v.s. Channel ID Distribution-1st \
Pulse-Overall;channelId;Tot", 10001, -0.5, 10000.5, 800, -500., 2000.);
  hnlvsChid = new TH2F("hnlvsChid", "Number of Leading Edges v.s. Channel Id;N Edge",
    10001, -0.5, 10000.5, 15, -1.5, 13.5);
  hntvsChid = new TH2F("hntvsChid", "Number of Trailing Edges v.s. Channel Id;N Edge",
    10001, -0.5, 10000.5, 15, -1.5, 13.5);
  hnl_ntvsChid = new TH2F("hnl_ntvsChid", "N-Leading_Edge - N-Trailing-Edge v.s. \
Channel Id;channel Id;nl - nt", 10001, -0.5, 10000.5, 17, -8.5, 8.5);

  fFolder->Add(hSecLen);      fFolder->Add(hFragLen);   fFolder->Add(hCh);
  fFolder->Add(htot);         fFolder->Add(hnlvsChid);  fFolder->Add(hntvsChid);
  fFolder->Add(hnl_ntvsChid);
} // end member function CreateHistos
